package com.future.service.Impl;


import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.future.allUtils.utils.CacheClient;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.*;
import com.future.domain.DTO.PageDTO;
import com.future.domain.vo.*;
import com.future.mapper.*;
import com.future.service.AdminService;
import com.future.service.IAnswerSheetService;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.future.allUtils.constants.RedisCacheConstants.ANSWER_SHEET_PREFIX;
import static com.future.allUtils.constants.RedisCacheConstants.PERSONAL_HEALTH_PREFIX;
import static com.future.allUtils.constants.RedisConstants.USER_QUESTIONNAIRE_KEY;
@Slf4j
@Service
public class IAnswerSheetServiceImpl extends ServiceImpl<AnswerSheetMapper, AnswerSheet> implements IAnswerSheetService {

    @Resource
    private AnswerSheetMapper answerSheetMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private HealthDetailMapper healthDetailMapper;

    @Resource
    private QuestionnaireResponseMapper questionnaireResponseMapper;

    @Resource
    private CacheClient cacheClient;

    @Resource
    private AdminService adminService;

    @Resource
    private UserMapper userMapper;
    @Autowired
    private UserClassMapper userClassMapper;

    @Autowired
    private QuestionnaireMapper questionnaireMapper;




    /**
     *  分页查询所有问卷的平均得分
     *  @param pageNum  页码
     *  @param pageSize 每页条数
     *  @return
     */
    @Override
    public Result getEveryAverage(Integer pageNum, Integer pageSize) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        //查发布的问卷
        List<Object> objects = questionnaireMapper.selectObjs(new LambdaQueryWrapper<Questionnaire>()
                .eq(Questionnaire::getPublishStatus, 1)
                .eq(Questionnaire::getCreatorId, currentUserId)
                .lt(Questionnaire::getExpiredAt, LocalDateTime.now())
                .select(Questionnaire::getId));
        List<Long> idList = objects.stream().map(o -> (Long) o).collect(Collectors.toList());
        if(idList.isEmpty()){
            return Result.ok(PageDTO.empty(new Page<>()));
        }
        log.info(idList.toString());

        if(!accessPage(pageNum,pageSize)){
            return Result.fail("页码传递错误");
        }
        Integer startIndex = (pageNum - 1) * pageSize;

        List<QuestionnaireResponse> questionnaireResponses = questionnaireResponseMapper.selectByPage(startIndex, pageSize,idList);
        int total = idList.size();
        double pages = Math.ceil((double) total / pageSize);

        PageDTO<QuestionnaireResponse> pageDTO = new PageDTO<>();
        pageDTO.setTotal((long) total);
        pageDTO.setRows(questionnaireResponses);
        pageDTO.setTotalPage(Math.round(pages));

        return Result.ok(pageDTO);
    }

    @Override
    public Result getMyHistoryScore(Integer pageNum, Integer pageSize) {
        //获取当前用户的id
        Long currentUserId = SecurityUtils.getCurrentUserId();
        //获取个人的健康详情
        HealthDetailVO healthDetail = cacheClient.queryWithPassThrough(PERSONAL_HEALTH_PREFIX, currentUserId, HealthDetailVO.class, id -> healthDetailMapper.getHealthDetail(currentUserId), 7L, TimeUnit.DAYS);
        if(healthDetail == null) {
            return Result.ok(
                    new HashMap<String,Object>(){{
                        put("pageDTO",PageDTO.empty(new Page<>()));
                        put("healthDetail",healthDetail);
                    }}
            );
        }
        //处理参数
        if(!accessPage(pageNum,pageSize) ){
            return Result.fail("参数传递错误");
        }
        //  分页查询(计算起始索引)
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex =  startIndex+pageSize-1;
        List<SAnswerSheetVo> healthDetailList = new ArrayList<>();
        //降序查询缓存
        Set<String> range = stringRedisTemplate.opsForZSet().reverseRange(ANSWER_SHEET_PREFIX + currentUserId, startIndex, endIndex);
        if(range != null && !range.isEmpty()){
            healthDetailList = range.stream().map(s -> JSONUtil.toBean(s, SAnswerSheetVo.class)).collect(Collectors.toList());
        }else{
            //未命中，查询数据库
            healthDetailList = answerSheetMapper.getHistory(new HashMap<String,Object>(){
                {
                    put("start_index",startIndex);
                    put("page_size",pageSize);
                    put("user_id",currentUserId);
                }
            });
            log.info("healthDetail:{}",healthDetailList);
            if(healthDetailList != null && !healthDetailList.isEmpty()){
                Map<String, Double> map = new HashMap<>();
                healthDetailList.forEach(sAnswerSheetVo -> {
                    // 计算时间戳作为分数
                    double score = (double) sAnswerSheetVo.getCompletedAt()
                            .atZone(ZoneId.systemDefault())
                            .toInstant()
                            .toEpochMilli();
                    // 存储JSON字符串和对应的分数
                    map.put(JSONUtil.toJsonStr(sAnswerSheetVo), score);
                });

                // 创建TypedTuple集合
                Set<ZSetOperations.TypedTuple<String>> tuples = new HashSet<>();
                for (Map.Entry<String, Double> entry : map.entrySet()) {
                    // 将每个键值对转换为TypedTuple对象
                    ZSetOperations.TypedTuple<String> tuple = ZSetOperations.TypedTuple
                            .of(entry.getKey(), entry.getValue());
                    tuples.add(tuple);
                }
               // 批量添加到有序集合
                stringRedisTemplate.opsForZSet().add(ANSWER_SHEET_PREFIX + currentUserId, tuples);
                //重建缓存
               // stringRedisTemplate.opsForList().rightPushAll(ANSWER_SHEET_PREFIX + currentUserId,healthDetailList.stream().map(JSONUtil::toJsonStr).collect(Collectors.toList()));
                //设置过期时间
                stringRedisTemplate.expire(ANSWER_SHEET_PREFIX + currentUserId,7, TimeUnit.DAYS);
            }else{
                return Result.ok(PageDTO.empty(new Page<>()));
            }

        }
        //总次数
        Set<String> members = stringRedisTemplate.opsForSet().members(USER_QUESTIONNAIRE_KEY + currentUserId);
        long totalCount =0L;
        if (members != null && !members.isEmpty()) {
            totalCount =  members.size();
        }else{
            List<AnswerSheet> answerSheets = answerSheetMapper.selectList(new QueryWrapper<AnswerSheet>().eq("user_id", currentUserId));
            if(answerSheets != null && !answerSheets.isEmpty()){
                totalCount =  answerSheets.size();

                //重建缓存
                stringRedisTemplate.opsForSet().add(USER_QUESTIONNAIRE_KEY + currentUserId, answerSheets.stream().map(AnswerSheet::getQuestionnaireId).map(String::valueOf).distinct().toArray(String[]::new));
                stringRedisTemplate.expire(USER_QUESTIONNAIRE_KEY+currentUserId,7, TimeUnit.DAYS);
            }else{
                HashMap<String,Object> map = new HashMap<>();
                map.put("pageDTO", new PageDTO<>().setRows(Collections.emptyList()).setTotalPage(0L).setTotal(0L));
                map.put("healthDetail",healthDetail);
                return Result.ok(map);
            }
        }
        //计算总页数
        Long totalPages = Math.round(Math.ceil((double) totalCount / pageSize));

        PageDTO<SAnswerSheetVo> pageDTO = new PageDTO<>();
        pageDTO.setTotalPage(totalPages).setTotal(totalCount).setRows(healthDetailList);
        Map<String ,Object> map = new HashMap<>();
        map.put("pageDTO",pageDTO);
        map.put("healthDetail",healthDetail);
        return Result.ok(map);
    }

    /**
     *  获得所有用户的健康详情
     */
    @Override
    public Result getHealthTable(Integer pageNum, Integer pageSize,String studentName) {

        Long currentUserId = SecurityUtils.getCurrentUserId();


        List<Integer> userRole = userMapper.getUserRole(currentUserId);
        if(userRole == null||userRole.isEmpty() ){
            return Result.fail("用户角色错误");
        }
        Long classId = 0L;
        if(!userRole.contains(3)){
            Long classIdByUserId = adminService.getClassIdByUserId(currentUserId);
            if(classIdByUserId != null){
                classId = classIdByUserId;
            }else{
                return Result.fail("当前用户没有管理班级");
            }
        }



        if(!accessPage(pageNum,pageSize)){
            return Result.fail("参数传递错误");
        }
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex =  startIndex+pageSize-1;
        //从redis中查


        //从数剧库中查
        Long finalClassIdByUserId = classId;
        List<HealthDetailVO> healthList = healthDetailMapper.getHealthList(new HashMap<String,Object>(){
            {
                put("start_index",startIndex);
                put("page_size",pageSize);
                put("real_name",studentName);
                put("class_id", finalClassIdByUserId);
            }
        });

        //总次数
        Long healthCount = healthDetailMapper.getHealthCount(studentName,finalClassIdByUserId,0);
        //警告人数
        Long warn = healthDetailMapper.getHealthCount(studentName, finalClassIdByUserId, 1);


        log.info("healthCount:{}",healthCount);
        //总页数
        Long totalPage = Math.round(Math.ceil((double) healthCount / pageSize));
        log.info("totalPage:{}",totalPage);
        if(healthList.isEmpty()){
            return Result.ok(PageDTO.empty(new Page<>()));
        }
        //分页
        PageDTO<HealthDetailVO> pageDTO = new PageDTO<>();
        pageDTO.setTotalPage(totalPage).setTotal(healthCount).setRows(healthList);
        HashMap<String,Object> map = new HashMap<>();
        map.put("pageDTO",pageDTO);
        map.put("warn",warn);



        return Result.ok(map);
    }
    /**
     *  获得单个问卷的学生作答详情
     *  @param pageNum  页码
     *  @param pageSize 每页条数
     *  @param id 问卷id
     *  @return
     */
    @Override
    public Result getSingle(Integer pageNum,Integer pageSize,Long id) {
        if(!accessPage(pageNum,pageSize)){
            return Result.fail("参数传递错误");
        }
        int startIndex = (pageNum - 1) * pageSize;

        List<AnswerSheetVO> healthDetailByPage = answerSheetMapper.getHealthDetailByPage(new HashMap<String,Object>(){
            {
                put("start_index",startIndex);
                put("page_size",pageSize);
                put("questionnaire_id",id);
            }
        });
        Long total = answerSheetMapper.selectCount(new LambdaQueryWrapper<AnswerSheet>().eq(AnswerSheet::getQuestionnaireId, id));


        Long num = answerSheetMapper.selectCount(new QueryWrapper<AnswerSheet>().lt("total_score", 45).eq("questionnaire_id", id));

        PageDTO<AnswerSheetVO> pageDTO = new PageDTO<>();
        pageDTO.setRows(healthDetailByPage)
                .setTotalPage(Math.round(Math.ceil((double) total /pageSize)))
                .setTotal(total);
        return Result.ok(new HashMap<String,Object>(){
            {
                put("pageDTO",pageDTO);
                put("warning",num);
            }
        });
    }
    /**
     *  更新建议
     *  @param id
     *  @param suggestion
     *  @return
     */
    @Override
    public Result updateByT(Long id,String suggestion) {
        if(suggestion != null && !suggestion.isEmpty()){
            UpdateWrapper<AnswerSheet> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id",id);
            log.info(suggestion);
            updateWrapper.set("suggestion",suggestion);
            boolean update = update(updateWrapper);
            if(update){
                return Result.ok("更新成功");
            }return Result.fail("更新失败");
        }
        return Result.fail("建议不能为空");
    }
    /**
     *  获取建议
     *  @param pageNum  页码
     *  @param pageSize 每页条数
     *  @return
     */
    @Override
    public Result getSuggestion(Long pageNum, Long pageSize) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if(!accessPage(pageNum.intValue(),pageSize.intValue())){
            return Result.fail("参数传递错误");
        }
        Page<AnswerSheet> answerSheetPage = answerSheetMapper.selectPage(
                new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<AnswerSheet>()
                        .eq(AnswerSheet::getUserId, currentUserId)
                        .select(AnswerSheet::getSuggestion)
                        .orderByDesc(AnswerSheet::getCreatedAt)
        );
        List<String> collect = answerSheetPage.getRecords().stream().map(AnswerSheet::getSuggestion).collect(Collectors.toList());


        PageDTO<String> pageDTO = new PageDTO<>();

        pageDTO.setRows(collect);
        pageDTO.setTotal(answerSheetPage.getTotal());
        pageDTO.setTotalPage(answerSheetPage.getPages());
        return Result.ok(pageDTO);
    }

    @Override
    public Result getNoted(Integer pageNum, Integer pageSize) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        List<Integer> userRole = userMapper.getUserRole(currentUserId);

        // 分页查询
        // 检查问卷参数
        if(!accessPage(pageNum, pageSize)){
            return Result .fail("参数传递错误");
        }
        int startIndex = (pageNum - 1) * pageSize;


        List<HealthDetail> notedStudents = null;
        if(userRole.contains(3)){
                 notedStudents = healthDetailMapper.getNotedStudents(new HashMap<String, Object>() {
                    {
                        put("start_index", startIndex);
                        put("page_size", pageSize);
                    }
                });
        }else{
            Long classIdByUserId = adminService.getClassIdByUserId(currentUserId);
            List<Long> ids   = userClassMapper.selectList(new QueryWrapper<UserClass>().eq("class_id", classIdByUserId)).stream().map(UserClass::getUserId).collect(Collectors.toList());
            notedStudents = healthDetailMapper.getNotedStudents(new HashMap<String, Object>() {
                {
                    put("start_index", startIndex);
                    put("page_size", pageSize);
                    put("user_ids",ids);
                }
            });
        }
        Long total = healthDetailMapper.selectCount(new QueryWrapper<HealthDetail>().lt("score/total_size  ", 60));
        Long totalPage = Math.round(Math.ceil((double) total /pageSize));





        //  封装分页结果
        PageDTO<HealthDetail> pageDTO = new PageDTO<>();
        pageDTO.setRows(notedStudents);
        pageDTO.setTotal(total);
        pageDTO.setTotalPage(totalPage);

        return Result.ok(pageDTO);


    }

    @Override
    public Result selectOne(Long id) {
        QuestionnaireResponseVO questionnaireResponseVO = questionnaireResponseMapper.selectOne(id);
        if(questionnaireResponseVO == null){
            return Result.fail("未找到");
        }
        return Result.ok(questionnaireResponseVO);
    }

    @Override
    public Result getClassStudents() {
        //获取老师管理的班级
        Long currentUserId = SecurityUtils.getCurrentUserId();
        //获取当前用户角色
        List<Integer> userRole = userMapper.getUserRole(currentUserId);
        if(userRole.contains(3)){
            Long l = userClassMapper.selectCount(null);
            List<HealthDetail> healthDetails = healthDetailMapper.selectList(null);
            OptionalDouble average = healthDetails.stream().mapToDouble(HealthDetail::getAverageScore).average();
            if(average.isPresent()){
                double averageScore = average.getAsDouble();
                return Result.ok(new HashMap<String,Object>(){
                    {
                        put("averageScore",averageScore);
                        put("totalStudents",l);
                    }
                });
            }
        }
        String s = stringRedisTemplate.opsForValue().get("TEACHER:CLASS:ID" + currentUserId);
        Long classId=0L;
        List<Long> studentIds = new ArrayList<>();
        if(s== null){
            Long id = adminService.getClassIdByUserId(currentUserId);
            if(id == null){
                return Result.ok(new HashMap<String,Object>(){
                    {
                       put("totalStudents",0);
                       put("averageScore",0);
                    }
                });
            }else{
                classId = id;
                stringRedisTemplate.opsForValue().set("TEACHER:CLASS:ID" + currentUserId,classId.toString(),7L,TimeUnit.DAYS);
            }
        }

        //获取班级的学生id
        List<String> range = stringRedisTemplate.opsForList().range("TEACHER:CLASS:STUDENT:ID" + classId, 0, -1);
        if(range == null || range.isEmpty()){
            List<UserClass> userClasses = userClassMapper.selectList(new QueryWrapper<UserClass>().eq("class_id", classId));
            List<Long>ids = userClasses.stream().map(UserClass::getUserId).collect(Collectors.toList());
            if(ids.isEmpty()){
                return Result.ok("班级下没有学生");
            }else{
                studentIds =ids;
                stringRedisTemplate.opsForList().rightPushAll("TEACHER:CLASS:STUDENT:ID" + classId,ids.stream().map(Object::toString).collect(Collectors.toList()));
                stringRedisTemplate.expire("TEACHER:CLASS:STUDENT:ID"+classId,7L,TimeUnit.DAYS);
            }
        }else{
            studentIds = range.stream().map(Long::valueOf).collect(Collectors.toList());
        }
        //获取班级平均分
        List<HealthDetail> classHTAB = healthDetailMapper.selectList(new QueryWrapper<HealthDetail>().in("user_id", studentIds));
        if(classHTAB == null || classHTAB.isEmpty()){
            return Result.ok(new HashMap<String,Object>(){
                {
                    put("totalStudents",0);
                    put("averageScore",0);
                }
            });
        }
        //计算班级平均分
        double sum = classHTAB.stream().mapToDouble(HealthDetail::getAverageScore).sum();
        double averageScore = sum / classHTAB.size();
        int totalStudents=  studentIds.size();
        return Result.ok(new HashMap<String,Object>(){
            {
                put("averageScore",averageScore);
                put("totalStudents",totalStudents);
            }
        });
    }

    @Override
    public Result getSingleById(Long aLong) {
        QuestionnaireResponseVOForT questionnaireResponseVOForT = questionnaireResponseMapper.selectByQuestionnaireId(aLong);
        return Result.ok(questionnaireResponseVOForT);
    }


    private boolean accessPage(Integer pageNum, Integer pageSize) {
        return pageNum >= 1 && pageSize >= 1;
    }


}